# vim: fdm=marker fmr={{{,}}} cms=#%s

import socket
import re

import misc
import errcode
import para

PERMANENT=0
ONESHOT=1

ERR_OK                          ="0000"

ERR_COMM_FAIL                   ="9000"
ERR_CALL_TIMEOUT                ="9001"
ERR_RESOURCE                    ="9002"
ERR_SVC_NOT_FOUND               ="9003"
ERR_DB                          ="9004"
ERR_MSG                         ="9005"
ERR_PARA                        ="9006"
ERR_NODE_NOT_FOUND              ="9007"
ERR_SVC_INVALID                 ="9008"
ERR_OUT_OF_SERVICE              ="9020"

ERR_SESSION_EXIST               ="4000"
ERR_SESSION_NOT_FOUND           ="4001"
ERR_SESSION_CREATE_FAIL         ="4002"
ERR_SESSION_SID_INVALID         ="4003"
ERR_SESSION_KEY_NOT_FOUND       ="4004"
ERR_SESSION_PUTKEY_FAIL         ="4005"
ERR_SESSION_VAL_NOT_INT         ="4006"
ERR_SESSION_MODKEY_FAIL         ="4007"
ERR_SESSION_SID_DISCORD         ="4008"
ERR_SESSION_KEY_FULL            ="4009"

ERR_SECURE_GENERR               ="4100"
ERR_SECURE_NOKEY                ="4101"
ERR_SECURE_VERIFYFAIL           ="4102"

ERR_MAILFWD_BLACK               ="4300"

ERR_CONFIRM_APP_ID_NOT_FOUND    ="4500"
ERR_CONFIRM_SEQ_INVALID         ="4501"
ERR_CONFIRM_SEQ_NOT_FOUND       ="4502"
ERR_CONFIRM_ID_NOT_MATCH        ="4503"
ERR_CONFIRM_CD_NOT_MATCH        ="4504"

class error:
#{{{
    def __init__(self, errcode):
        self.errcode=errcode
#}}}

class svcnode:
    def __init__(self, addr, mode=ONESHOT):
#{{{
        if mode != PERMANENT and mode != ONESHOT:
            mode=PERMANENT
        self.mode=mode
        self.sock=None
        res=re.search(":", addr)
        if not res:
            raise error(errcode.RET_ERR_PARA)
        try:
            key,value=addr.split(':')
            self.host=key
            self.port=int(value)
        except ValueError:
            raise error(errcode.RET_ERR_PARA)
#}}}

    def __del__(self):
#{{{
        if self.sock:
            self.sock.close()
#}}}

    def call(self, svc, req):
#{{{
        if not self.sock:
            self.sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                self.sock.connect((self.host, self.port))
            except (socket.gaierror,socket.error):
                raise error(errcode.RET_ERR_CONNECT)
        try:
            msg=''
            msg,size=para.put_item(msg, svc);
            msg+=req
            msg=misc.wrap_size(msg)
            self.sock.sendall(msg)
            buf=self.sock.recv(misc.MSG_SIZE_SIZE)
            if len(buf) == 0:
                raise error(errcode.RET_ERR_ABORT)
            left_size=int(buf, base=16)
            resp=''
            while left_size > 0:
                buf=self.sock.recv(left_size)
                if len(buf) == 0:
                    raise error(errcode.RET_ERR_ABORT)
                resp+=buf
                left_size-=len(buf)
        except socket.error:
            raise error(errcode.RET_ERR_ABORT)
        if self.mode == ONESHOT:
            self.sock.close()
            self.sock=None
        return resp
#}}}
